package io.github.cubelitblade.librarymanagementbackend.service;

import io.github.cubelitblade.librarymanagementbackend.dto.UserBookRequestDTO;
import io.github.cubelitblade.librarymanagementbackend.entity.Book;
import io.github.cubelitblade.librarymanagementbackend.entity.BorrowRecord;
import io.github.cubelitblade.librarymanagementbackend.exception.BusinessException;
import io.github.cubelitblade.librarymanagementbackend.vo.BookBriefVO;
import io.github.cubelitblade.librarymanagementbackend.vo.BorrowResponseVO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
public class UserBorrowFacade {
    private final UserService userService;
    private final BorrowService borrowService;
    private final BookService bookService;

    UserBorrowFacade(UserService userService, BorrowService borrowService, BookService bookService) {
        this.userService = userService;
        this.borrowService = borrowService;
        this.bookService = bookService;
    }

    /**
     * 提供借书服务。
     * <p>通过传入的 {@link UserBookRequestDTO} 实体，构建相应借书记录并且插入到数据库中。</p>
     *
     * @param userBookRequestDTO 包含用户ID和所借书籍ID的 {@link UserBookRequestDTO} 实体。
     * @return 如果借阅记录插入成功，则返回相应的 {@link  BorrowResponseVO} 实体。
     * @throws BusinessException 当传入的 {@link UserBookRequestDTO} 的 {@code userID} 对应的用户不存在 {@code bookID}
     *                           对应的书籍不存在， {@code bookID} 对应书籍的 {@code stock} 字段的值小于 {@code 1}
     *                           或数据库操作异常时。
     */
    @Transactional
    public BorrowResponseVO borrowBook(UserBookRequestDTO userBookRequestDTO) {
        Integer userId = userBookRequestDTO.getUserId();
        Integer bookId = userBookRequestDTO.getBookId();

        if (!userService.existsUser(userId)) {
            throw BusinessException.userNotFound();
        }

        if (!bookService.existBook(bookId)) {
            throw BusinessException.bookNotFound();
        }

        BorrowRecord borrowRecord = borrowService.borrowBook(userId, bookId);

        return BorrowResponseVO.of(borrowRecord, BookBriefVO.of(bookService.decreaseStock(bookId, 1)));
    }

    /**
     * 通过用户ID查找对应的借阅记录。
     * <p>此方法查找借阅记录的SQL视图。视图在查询时会在 {@code deadline} 字段早于服务器时间，且状态仍为
     * {@code BorrowStatus.BORROWING} 的记录的 {@code status} 字段更改为 {@code BorrowStatus.OVERDUE} 。</p>
     *
     * @param userId 待查找记录的用户ID。
     * @return 此用户ID对应用户的借阅记录列表。
     */
    public List<BorrowResponseVO> listBorrowsByUser(Integer userId) {
        return BorrowResponseVO.ofList(borrowService.listBorrows(userId));
    }

    /**
     * 提供还书服务。
     * <p>在数据库中查找对应的借阅记录，如果存在，且状态为 {@code BorrowStatus.BORROWING} 时，将其状态更改为
     * {@code BorrowStatus.RETURNED} ，并将库存增加。</p>
     *
     * @param borrowRecordId 借阅记录的ID。
     * @return 如果成功更新记录，则返回更新后的借阅记录。
     * @throws BusinessException 当借书记录不存在，借书记录的 {@code status} 字段已经为 {@code BorrowStatus.RETURNED}
     *                           ，图书不存在或归还后导致图书库存超过上限时。
     */
    @Transactional
    public BorrowResponseVO returnBook(Integer borrowRecordId) {
        BorrowRecord borrowRecord = borrowService.returnBook(borrowRecordId);
        return BorrowResponseVO.of(borrowRecord, BookBriefVO.of(bookService.increaseStock(borrowRecord.getBookId(), 1)));
    }

    /**
     * 查找符合条件且状态为 {@code BORROWING} 的借阅记录。
     *
     * @param userId 用户ID。
     * @param bookId 书籍ID。
     * @return 如果查找到记录，则返回此记录；否则返回 {@code null} 。
     * @throws BusinessException 当用户不存在或书籍不存在时。
     */
    public BorrowResponseVO findActiveBorrowRecord(Integer userId, Integer bookId) {
        if (!userService.existsUser(userId)) {
            throw BusinessException.userNotFound();
        }

        Book book = bookService.getById(bookId);
        if (book == null) {
            throw BusinessException.bookNotFound();
        }

        BorrowRecord borrowRecord = borrowService.findActiveBorrowRecord(userId, bookId);
        if (borrowRecord == null) {
            return null;
        }

        return BorrowResponseVO.of(borrowRecord, BookBriefVO.of(book));
    }
}
